/*
 * np_str.h
 *
 *  Created on: Nov 23, 2010
 *      Author: jeff_zheng
 *   Copyright: NetPerform Technology
 */

#ifndef NP_STR_H_
#define NP_STR_H_

#ifdef __cplusplus
extern "C" {
#endif

typedef char* np_cstr;

typedef struct np_str_s
{
	np_cstr		str;
	uint32_t 	length;
}np_str;

typedef struct np_cstr_array_s
{
	np_cstr* 	array;
	np_bool* 	alloc_flags;

	uint32_t	max_size;
	uint32_t 	length;
	np_bool		array_alloc_flag;
	np_bool		flags_alloc_flag;
	np_cstr		trailing_base;
	uint32_t	total_trailing_bytes;
	uint32_t	used_trailing_bytes;
}np_cstr_array;


#define np_str_declare(name, size) \
	char local_##name[size]; \
	np_str name = {local_##name, size};


static inline np_cstr np_str_from_ip(np_str* str_dst, size_t length, uint32_t addr)
{
	uint8_t* p_uint8 = (uint8_t*)&(addr);
	snprintf(str_dst->str, str_dst->length, "%u.%u.%u.%u",
			p_uint8[0],p_uint8[1],p_uint8[2],p_uint8[3]);
	str_dst->str[length-1]=0;
	return str_dst->str;
}

static inline  int np_cstr_to_u32(const np_cstr p_cstr,  uint32_t * ret_u32)
{
	char* endstr;
	uint32_t result;
	result = strtoul(p_cstr, &endstr, 10);
	if(endstr==p_cstr)
	{
		return -1;
	}
	*ret_u32 = result;
	return 0;
}
static inline void np_cstr_array_destroy(np_cstr_array* array)
{
	free(array);
}
static inline np_cstr_array* np_cstr_array_create(uint32_t max_size, uint32_t max_bytes_total)
{
	np_cstr_array* ret_array;
	uint32_t trailing_bytes = max_bytes_total*2;
	ret_array = (np_cstr_array*)malloc(max_size*(sizeof(np_bool)+sizeof(np_cstr))+
										sizeof(np_cstr_array)+trailing_bytes);

	if(ret_array==NULL)
		return NULL;
	ret_array->total_trailing_bytes = trailing_bytes;
	ret_array->array_alloc_flag = np_true;
	ret_array->flags_alloc_flag = np_true;
	ret_array->array = (np_cstr*)(ret_array+1);
	ret_array->max_size = max_size;
	ret_array->alloc_flags = (np_bool*)(ret_array->array+max_size);
	ret_array->length = 0;
	ret_array->used_trailing_bytes = 0;
	ret_array->trailing_base = (np_cstr)(ret_array->alloc_flags + max_size);

	return ret_array;
}

static inline int np_cstr_array_add(np_cstr_array* array, const np_cstr new_str)
{
	np_cstr new_array_str;
	uint32_t new_str_len = strlen(new_str);
	if((array->used_trailing_bytes + new_str_len + 1)>array->total_trailing_bytes)
	{
		return -1;
	}
	if(array->length>=array->max_size)
	{
		return -1;
	}

	new_array_str = array->trailing_base + array->used_trailing_bytes;
	array->used_trailing_bytes += (new_str_len+1);
	array->array[array->length] = new_array_str;
	array->length ++;
	if(new_str_len)
		strncpy(new_array_str, new_str, new_str_len);
	new_array_str[new_str_len]=0;
	return 0;
}

static inline np_cstr np_cstr_strip_new(const np_cstr cstr, char* tostrip)
{
	uint32_t len = strlen(cstr);
	uint32_t loop;
	static char* default_strip = (char*)" \t";
	if(tostrip==NULL)
		tostrip = default_strip;
	uint32_t strip_len = strlen(tostrip);

	for(loop=0; loop<len; loop++)
	{
		uint32_t l = 0;
		np_bool found = np_false;
		for(l=0;l<strip_len;l++)
		{
			if(cstr[loop]==tostrip[l])
			{
				found = np_true;
			}
		}
		if(!found)
		{
			break;
		}
	}
	char* ret = (char*)malloc(len - loop+1);
	if(len-loop)
	{
		strcpy(ret, cstr+loop);
	}
	else
		ret[0] = 0;
	return ret;
}

static inline np_cstr_array* np_cstr_split(const np_cstr cstr, char* splitter)
{
	uint32_t str_total_len = strlen(cstr);
	np_cstr_array* ret_array;

	ret_array = np_cstr_array_create(str_total_len/2, str_total_len);
	if(ret_array==NULL)
	{
		return NULL;
	}

	char* saveptr=NULL, *next_str;
	next_str = strtok_r(cstr, splitter, &saveptr);
	while(next_str)
	{
		if(0!=np_cstr_array_add(ret_array, next_str))
		{
			np_cstr_array_destroy(ret_array);
			return NULL;
		}
		next_str = strtok_r(NULL, splitter, &saveptr);
	}

	return ret_array;
}

#define np_cstr_array_for_each(substr, arr)	\
		do{uint32_t substrloop__; \
			for(substrloop__=0;substrloop__<arr->length;substrloop__++) {\
				substr = arr->array[substrloop__];
#define np_cstr_array_for_each_end() }}while(0);

#ifdef __cplusplus
}
#endif

#endif /* NP_STR_H_ */
